import * as echarts from 'echarts/core'
import { BarChart, GaugeChart, LineChart, PictorialBarChart, PieChart, RadarChart, SankeyChart, ScatterChart } from 'echarts/charts'
import type {
  BarSeriesOption,
  GaugeSeriesOption,
  LineSeriesOption,
  PictorialBarSeriesOption,
  PieSeriesOption,
  RadarSeriesOption,
  ScatterSeriesOption,
} from 'echarts/charts'
import {
  DataZoomComponent,
  DatasetComponent,
  GridComponent,
  LegendComponent,
  TitleComponent,
  ToolboxComponent,
  TooltipComponent,
  TransformComponent,
} from 'echarts/components'
import type {
  DatasetComponentOption,
  GridComponentOption,
  LegendComponentOption,
  TitleComponentOption,
  ToolboxComponentOption,
  TooltipComponentOption,
} from 'echarts/components'
import { LabelLayout, UniversalTransition } from 'echarts/features'
import { CanvasRenderer } from 'echarts/renderers'
import { useElementSize } from '@vueuse/core'

export type ECOption = echarts.ComposeOption<
  | BarSeriesOption
  | LineSeriesOption
  | PieSeriesOption
  | ScatterSeriesOption
  | PictorialBarSeriesOption
  | RadarSeriesOption
  | GaugeSeriesOption
  | TitleComponentOption
  | LegendComponentOption
  | TooltipComponentOption
  | GridComponentOption
  | ToolboxComponentOption
  | DatasetComponentOption
>

echarts.use([
  TitleComponent,
  LegendComponent,
  TooltipComponent,
  GridComponent,
  DatasetComponent,
  DataZoomComponent,
  TransformComponent,
  ToolboxComponent,
  BarChart,
  LineChart,
  PieChart,
  SankeyChart,
  ScatterChart,
  PictorialBarChart,
  RadarChart,
  GaugeChart,
  LabelLayout,
  UniversalTransition,
  CanvasRenderer,
])

/**
 * Echarts hooks函数
 * @param options - 图表配置
 * @param renderFun - 图表渲染函数(例如：图表监听函数)
 * @description 按需引入图表组件，没注册的组件需要先引入
 */
export function useEcharts(
  options: Ref<ECOption> | ComputedRef<ECOption>,
  renderFun?: (chartInstance: echarts.ECharts) => void,
) {
  const domRef = ref<HTMLElement>()

  const initialSize = { width: 0, height: 0 }
  const { width, height } = useElementSize(domRef, initialSize)

  let chart: echarts.ECharts | null = null

  function canRender() {
    return initialSize.width > 0 && initialSize.height > 0
  }

  function isRendered() {
    return Boolean(domRef.value && chart)
  }

  function update(updateOptions: ECOption) {
    if (isRendered()) {
      chart?.clear()
      chart?.showLoading({
        fontSize: 14,
        textColor: 'rgb(31, 31, 31)',
        maskColor: 'rgba(255, 255, 255, 0.8)',
      })
      chart!.setOption({ ...updateOptions, backgroundColor: 'transparent' })
      chart?.hideLoading()
    }
  }

  async function render() {
    if (domRef.value) {
      await nextTick()
      chart = echarts.init(domRef.value)
      if (renderFun)
        renderFun(chart)

      update(options.value)
    }
  }

  function resize() {
    chart?.resize()
  }

  function destroy() {
    chart?.dispose()
  }
  const scope = effectScope()

  scope.run(() => {
    watch([width, height], ([w, h]) => {
      initialSize.width = w
      initialSize.height = h
      const isReady = canRender()
      if (isReady) {
        isRendered() ? resize() : render()
      }
      else {
        destroy()
        chart = null
      }
    })

    watch(options, (newValue) => {
      update(newValue)
    }, { deep: true })
  })

  onScopeDispose(() => {
    destroy()
    scope.stop()
  })
  // 防止 echarts 页面 keepAlive 时，还在继续监听页面
  // onDeactivated(stop)
  return {
    domRef,
  }
}
